/**
 * @author Rid King
 * @since 2017-05-19
 * @version 2.0.0
 * @description 虚拟元素
 */

 import diff from './diff.js'

// 文档对象
const doc = document

class VirtualElement {
    /**
     * @function 构造方法
     */
    constructor (tagName) {
        // 当前元素标识
        this._key_ = 'vel_' + String(Math.random()).replace('.', '')
        this.init.apply(this, arguments)
    }

    /**
     * @function 初始化
     * @param tagName <String> // 标签名
     * @param viewer {Viewer} // 视图对象
    */
    init (tagName, viewer) {
        // 节点类型
        this.nodeType = NODETYPE.ELEMENT
        // 保存视图对象
        this._viewer = viewer
        // 标签名
        this.tagName = tagName
        // 属性集
        this.attributes = {}
        // 子元素数组
        this.childNodes = []
        // 事件对象
        this.events = {}
    }

    /**
     * @function 设置属性
     * @param key {String} // 属性名
     * @param value {String} // 属性值
    */
    setAttribute (key, value) {
        this.attributes[key] = value
    }

    /**
     * @function 添加子元素
     * @param vel {VirtualElement} // 子元素
    */
    appendChild (vel) {
        // 非元素不添加
        if (!(vel instanceof VirtualElement)) {
            return false
        }

        // 子元素加入子元素组
        this.childNodes.push(vel)
    }

    /**
     * @function 删除子元素
     * @param vel {VirtualElement} // 子元素
    */
    removeChild (vel) {
        // 非元素不添加
        if (!(vel instanceof VirtualElement)) {
            return false
        }

        // 过滤子节点
        this.childNodes.filter(node => {
            return node._key_ !== vel._key_
        })
    }

    /**
     * @function 替换子元素
     * @param vel {VirtualElement} // 被替换的子元素
     * @param replaceVel {VirtualElement} // 需要替换的子元素
    */
    replaceChild (vel, replaceVel) {
        // 非元素不添加
        if (!(vel instanceof VirtualElement)) {
            return false
        }

        // 子元素加入子元素组
        this.childNodes.map(node => {
            // 比较标识是否相同
            if (node._key_ === vel._key_) {
                return replaceVel
            }

            return node
        })
    }

    /**
     * @function 创建元素
     * @param tagName <String> // 标签名
     * @param viewer {Viewer} // 视图对象
     * @return {VirtualElement}
    */
    static createElement (tagName, viewer) {
        return new VirtualElement(tagName, viewer)
    }

    /**
     * @function 创建文本
     * @param textContent <String> // 文本
     * @return {VirtualElement}
    */
    static createTextNode (textContent) {
        return new VirtualText(textContent)
    }

    /**
    * @function 渲染成DOM
    * [@param isDaly {Boolean} // 是否延迟]
    * @return {HTMLElement}
    */
    render (isDaly) {
        // 创建标签
        let el = doc.createElement(this.tagName)
        // 设置标签的属性
        let attributes = this.attributes
        for (let key in attributes) {
            el.setAttribute(key, attributes[key])
        }

        // 事件绑定
        this.bindEvents(el, this.events)

        // 延迟添加子节点
        if (isDaly) {
            setTimeout(() => {
                this._renderChildNodes(el, isDaly)
            }, 20)
        }
        // 不延迟
        else {
            this._renderChildNodes(el, isDaly)
        }

        // 关联DOM元素
        this._el = el

        return el
    }

    /**
     * @function 渲染子元素节点
     * @param el {HTMLElement} // 父节点元素
     * [@param isDaly {Boolean} // 是否延迟]
    */
    _renderChildNodes (el, isDaly) {
        // 参数非元素不执行
        if (!(el instanceof HTMLElement)) {
            return false
        }

        // 依次创建子节点
        this.childNodes.forEach(item => {
            el.appendChild(item.render(isDaly))
        })
    }

    /**
     * @function 重新渲染
     * @param vel {VirtualElement} // 新虚拟元素对象
    */
    reRender (vel) {
        let _el = this._el
        // 元素比较
        // this.diff(vel)
        // 比较新老元素异同并更新
        // this.renderDiff(vel)

        diff(this._el, vel)
        
        // // 重新渲染
        // this._el = vel.render()
        // // 插入元素
        // _el.insertAdjacentElement('afterend', this._el)
        // // 删除原元素
        // _el.remove()
    }

    /**
     * @function 虚拟元素比对：1、如何比较两个两棵DOM树；2、如何记录节点之间的差异
     * @param vel {VirtualElement} // 新元素
    */
    renderDiff (vel) {
        // // 保存视图对象
        // this._viewer = viewer
        // // 标签名
        // this.tagName = tagName
        // // 属性集
        // this.attributes = {}
        // 事件对象
        // this.events = {}
        // // 子元素数组
        // this.childNodes = []
        // 节点类型不同
        if (this.nodeType !== vel.nodeType) {
            // 克隆元素
            this.clone(vel)
            // 重新渲染
            this.renderReplace()
        }
        // 元素节点
        else if (this.nodeType === NODETYPE.ELEMENT) {
            // 属性比较
            let attributes = this.attributes
        }
        // 文本节点
        else if (this.textContent !== vel.textContent){
            // 克隆元素
            this.clone(vel)
            // 重新渲染
            this.renderReplace()
        }

        // 含有子节点
        if (this.childNodes) {
            this.childNodes.forEach((item,i) => {
                item.renderDiff(vel.childNodes[i])
            })
        }
    }

    /**
     * @function 渲染替换
     * [@param vel {VirtualElement} // 新虚拟元素对象]
    */
    renderReplace (vel) {
        let _el = this._el
        vel = (vel instanceof VirtualElement) ? vel : this

        // 当前元素是标签元素
        if (this.type === NODETYPE.ELEMENT) {
            // 重新渲染
            this._el = vel.render()
            // 插入元素
            _el.insertAdjacentElement('afterend', this._el)
            // 删除原元素
            _el.remove()
        }
        // 当前元素是文本元素
        else {
            // 父级DOM节点
            let parentNode = this.parentNode._el
            // 同级的DOM元素
            let childNodes = Array.from(parentNode.childNodes)
            // 遍历子节点
            childNodes.forEach((node, i) => {
                if (node === this._el) {
                    // 插入节点
                    parentNode.insertBefore(this._el = vel.render(), node)
                    // 删除原节点
                    parentNode.removeChild(node)
                }
            })

            this.parentNode.replaceChild(this, vel)
        }
    }

    /**
     * @function 比对
    */
    diff (vel) {

    }

    /**
     * @function 克隆元素
     * @param vel {VirtualElement} // 虚拟元素
    */
    clone (vel) {
        // 保存视图对象
        this._viewer = vel.viewer
        // 保存节点类型
        this.type = vel.type
        // 标签名
        if (vel.hasOwnProperty('tagName')) {
            this.tagName = vel.tagName
        }
        else {
            delete this.tagName
        }
        // 属性集
        if (vel.hasOwnProperty('attributes')) {
            this.attributes = vel.attributes
        }
        else {
            delete this.attributes
        }
        // 子元素数组
        if (vel.hasOwnProperty('childNodes')) {
            this.childNodes = vel.childNodes
        }
        else {
            delete this.childNodes
        }
        // 事件对象
        if (vel.hasOwnProperty('events')) {
            this.events = vel.events
        }
        else {
            delete this.events
        }
        // 文本
        if (vel.hasOwnProperty('textContent')) {
            this.textContent = vel.textContent
        }
        else {
            delete this.textContent
        }
    }

    /**
     * @function 设置模型值
     * @param value {any} // 模型值
    */
    setValue (value) {
        this.attributes.value = value
    }

    /**
     * @function 监视模型
     * @param model {Object} // 模型
    */
    watchModel (model) {
      let me = this
      // 给元素添加更新事件
      this.addEventListener('modify', function (e, value) {
        // 设置模型值
        me.setValue(value)
        // 设置元素的值
        me.updateModel(model, value)
      })
    }

    /**
     * @function 更新模型
    */
    updateModel (model, value) {
      this._viewer.$sync(model, value)
      // this._watcher.aaa(value)
    }

    /**
     * @function 添加事件
     * @param eventName {String} // 事件名称
     * @param callback {Function} // 事件处理方法
    */
    addEventListener (eventName, callback) {
        // 获取事件处理方法数组
        let callers = this.events[eventName]
        callers = this.events[eventName] = callers || []
        // 添加事件处理
        callers.push(callback)
    }

    /**
     * @function 绑定事件
     * @param el {HTMLDocument} // 事件名称
     * @param events {Object} // 事件对象集合
    */
    bindEvents (el, events) {
        for(let key in events) {
            // 事件回调组
            let callers = events[key] || []
            // 模型更新事件
            if (key === 'modify') {
                // 输入事件
                el.addEventListener('keyup', (e) => {
                    callers.forEach(caller => {
                        caller(e, e.target.value)
                    })
                })
            }
        }
    }
}

// 虚拟文本元素
class VirtualText extends VirtualElement {
    /**
     * @function 初始化
     * @param textContent <String> // 文本
    */
    init (textContent, viewer) {
        // 节点类型
        this.nodeType = NODETYPE.TEXT
        // 保存视图对象
        this._viewer = viewer
        // 文本内容
        this.textContent = textContent
        // 属性集
        this.attributes = {}
    }

    /**
    * @function 渲染成DOM
    * @return {HTMLElement}
    */
    render () {
        // 创建文本元素
        let el = doc.createTextNode(this.textContent)
        // 关联DOM元素节点
        this._el = el

        return el
    }
}

// 节点类型
const NODETYPE = {
    ELEMENT: 1, // 元素
    TEXT: 3 // 文本
}

export default VirtualElement
export {NODETYPE}